package file

import (
	"fmt"
	"github.com/golang-module/carbon/v2"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cast"
	"hc_server/pkg/setting"
	"hc_server/pkg/util"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

// GetSize 获取文件大小
func GetSize(f multipart.File) (int, error) {
	content, err := ioutil.ReadAll(f)

	return len(content), err
}

// GetImageFullUrl 获取图片完整路径
func GetImageFullUrl(userId string, name string) string {
	return setting.GetConfig().App.PrefixUrl + "/file/" + userId + "/" + name
}

// GetAgentFileFullUrl 获取图片完整路径
func GetAgentFileFullUrl(userId string, name string) string {
	return setting.GetConfig().App.PrefixUrl + "/file/" + setting.GetConfig().App.AgentPath + userId + "/" + name
}

// GetImageName 获取图片名称
func GetImageName(name string) string {
	ext := path.Ext(name)
	fileName := strings.TrimSuffix(name, ext) + cast.ToString(time.Now().Unix())
	fileName = util.EncodeMD5(fileName)

	return fileName + ext
}

// GetFilePath 获取图片路径
func GetFilePath() string {
	return setting.GetConfig().App.FileSavePath
}

// GetFileFullPath 获取完整图片路径
func GetFileFullPath() string {
	return setting.GetConfig().App.RuntimeRootPath + GetFilePath()
}

// GetFileUserPath 通过用户id获取完整用户路径
func GetFileUserPath(userId string) string {
	return GetFileFullPath() + "user/" + setting.GetConfig().App.MerchantPath + userId + "/"
}

// GetRootFileFullPath 获取完整根路径
func GetRootFileFullPath() string {
	//wd, _ := os.Getwd()
	//fmt.Println(setting.GetConfig().App.RuntimeRootPath + GetFilePath())
	return setting.GetConfig().App.RuntimeRootPath + GetFilePath()
}

// CheckImageExt 验证图片扩展名
func CheckImageExt(fileName string) bool {
	ext := GetExt(fileName)
	for _, allowExt := range setting.GetConfig().App.ImageAllowExts {
		if strings.ToUpper(allowExt) == strings.ToUpper(ext) {
			return true
		}
	}

	return false
}

// CheckImageSize 验证图片大小
func CheckImageSize(f multipart.File) bool {
	size, err := GetSize(f)
	if err != nil {
		log.Println(err)
		logrus.Warn(err)
		return false
	}

	return size <= setting.GetConfig().App.ImageMaxSize*1024*1024
}

// CheckImage 验证图片是否存在
func CheckImage(src string) error {
	dir, err := os.Getwd()
	if err != nil {
		return fmt.Errorf("os.Getwd err: %v", err)
	}

	err = IsNotExistMkDir(dir + "/" + src)
	if err != nil {
		return fmt.Errorf("file.IsNotExistMkDir err: %v", err)
	}

	perm := CheckPermission(src)
	if perm == true {
		return fmt.Errorf("file.CheckPermission Permission denied src: %s", src)
	}

	return nil
}

// GetExt 获取文件后缀
func GetExt(fileName string) string {
	return path.Ext(fileName)
}

// CheckNotExist 检查该文件是否不存在
func CheckNotExist(src string) bool {
	_, err := os.Stat(src)

	return os.IsNotExist(err)
}

// CheckPermission 检查该文件是否没有权限
func CheckPermission(src string) bool {
	_, err := os.Stat(src)

	return os.IsPermission(err)
}

// IsNotExistMkDir 创建一个文件夹，如果文件夹不存在则创建
func IsNotExistMkDir(src string) error {
	if notExist := CheckNotExist(src); notExist == true {
		if err := MkDir(src); err != nil {
			return err
		}
	}

	return nil
}

// MkDir 创建一个文件夹
func MkDir(src string) error {
	err := os.MkdirAll(src, os.ModePerm)
	if err != nil {
		return err
	}

	return nil
}

// Open 打开一个文件
func Open(name string, flag int, perm os.FileMode) (*os.File, error) {
	f, err := os.OpenFile(name, flag, perm)
	if err != nil {
		return nil, err
	}

	return f, nil
}

// MustOpen 最大限度地尝试打开文件
func MustOpen(fileName, filePath string) (*os.File, error) {
	dir, err := os.Getwd()
	if err != nil {
		return nil, fmt.Errorf("os.Getwd err: %v", err)
	}

	src := dir + "/" + filePath
	perm := CheckPermission(src)
	if perm == true {
		return nil, fmt.Errorf("file.CheckPermission Permission denied src: %s", src)
	}

	err = IsNotExistMkDir(src)
	if err != nil {
		return nil, fmt.Errorf("file.IsNotExistMkDir src: %s, err: %v", src, err)
	}

	f, err := Open(src+fileName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
	if err != nil {
		return nil, fmt.Errorf("Fail to OpenFile :%v", err)
	}

	return f, nil
}

// GetRandomFileName 获取随机文件名
func GetRandomFileName() string {
	return cast.ToString(carbon.Now().Timestamp()) + cast.ToString(util.GenerateRandomNumber(3))
}

// MoveFileTempToUser 把文件从临时空间移动到用户的文件夹
func MoveFileTempToUser(userId string, fileName string) error {
	source := GetFileFullPath() + fileName
	target := GetFileFullPath() + userId + "/" + fileName

	err := os.MkdirAll(filepath.Dir(GetFileFullPath()+userId+"/"), os.ModePerm)
	if err != nil {
		return err
	}

	err = os.Rename(source, target)
	if err != nil {
		fmt.Println(err)
		return err
	}

	return nil
}

// RemoveDir 删除指定的文件夹及其所有内容
func RemoveDir(userId string) error {
	source := GetFileFullPath() + "temp/" + userId + "/"
	return os.RemoveAll(source)
}

// MoveDirTempToUser 把文件夹从临时空间移动到用户的文件夹
func MoveDirTempToUser(userId string) error {
	source := GetFileFullPath() + "temp/" + userId + "/"
	target := GetFileFullPath() + "user/" + userId + "/"

	srcInfo, err := os.Stat(source)
	if err != nil {
		return err
	}

	if !srcInfo.IsDir() {
		return &os.PathError{Op: "copy", Path: source, Err: os.ErrNotExist}
	}

	_, err = os.Stat(target)
	if os.IsNotExist(err) {
		err = os.MkdirAll(target, srcInfo.Mode())
		if err != nil {
			return err
		}
	}

	entries, err := ioutil.ReadDir(source)
	if err != nil {
		return err
	}

	for _, entry := range entries {
		srcPath := filepath.Join(source, entry.Name())
		dstPath := filepath.Join(target, entry.Name())

		if entry.IsDir() {
			if err = MoveDirTempToUser(userId); err != nil {
				return err
			}
		} else {
			if err = CopyFile(srcPath, dstPath); err != nil {
				return err
			}
		}
	}

	return nil
}

func CopyFile(src, dst string) error {
	srcFile, err := os.Open(src)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	dstFile, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer dstFile.Close()

	_, err = io.Copy(dstFile, srcFile)
	return err
}
